package android_testsuite.mytest.network_test;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Date;

import android_testsuite.mytest.util.Const;

/**
 * @author Ren Hui
 * @since 1.0.1.058
 */
public class UdpRunnable implements Runnable {
    // 收包的次数
    private int mReceiveTimes = 0;
    // 出错的包数
    private int mErrorTimes = 0;
    // 弱引用
    private WeakReference<SocketActivity> mActivityWeakReference;
    // 检测的IP
    private String mIp;
    // 包大小
    private int mLength = 1024;
    //发送时间
    private Date[] mSentDates;
    //接收时间
    private Date[] mReceiveDates;

    public UdpRunnable(SocketActivity activity, String ip, int length) {
        super();
        this.mIp = ip;
        this.mLength = length;
        this.mActivityWeakReference = new WeakReference<SocketActivity>(activity);
    }

    @Override
    public void run() {
        UdpFun udpConnect = new UdpFun();
        udpConnect.func();
    }

    private class UdpFun {
        private byte[] buffer;
        private DatagramSocket mDataSocket = null;

        public UdpFun() {
            buffer = new byte[mLength];
            try {
                mDataSocket = new DatagramSocket();
                mDataSocket.setSoTimeout(Const.SO_TIMEOUT);
            } catch (SocketException e) {
                showLogMsg(e.toString() + "\n");
            }
        }

        private DatagramPacket send(String host, int port, byte[] bytes) throws IOException {
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length,
                    InetAddress.getByName(host), port);
            mDataSocket.send(dp);
            return dp;
        }

        private void receive() {
            try {
                DatagramPacket dp = new DatagramPacket(buffer, buffer.length);
                mDataSocket.receive(dp);
                String info = new String(dp.getData(), 0, dp.getLength());
                int num = Integer.parseInt(info);
                mReceiveDates[num] = new Date();
                mReceiveTimes++;
            } catch (SocketTimeoutException e) {
                showLogMsg(e.toString()+"\n");
                mErrorTimes++;
            } catch (IOException e) {
                mErrorTimes++;
                showLogMsg(e.toString() + "\n");
            }
        }

        public void close() {
            if (!mDataSocket.isClosed()) {
                // close之前将统计的方法进行下去。
                mDataSocket.close();
            }
        }

        public void func() {
            // 测试丢包率功能
            String serverHost = mIp;
            int serverPort = Const.ECHO_PORT;
            mSentDates = new Date[Const.SEND_TIMES];
            mReceiveDates = new Date[Const.SEND_TIMES];
            for (int i = 0; i < Const.SEND_TIMES; i++) {
                buffer = Integer.toString(i).getBytes();
                try {
                    send(serverHost, serverPort, buffer);
                } catch (IOException e) {
                    showLogMsg(e.toString() + "\n");
                }
                mSentDates[i] = new Date();
            }

            for (int i = 0; i < Const.SEND_TIMES; i++) {
                receive();
            }

            // 计算丢包率
            int re = mErrorTimes * 100 / Const.SEND_TIMES;
            long sum = 0;
            double avg = 0;
            for (int i = 0; i < Const.SEND_TIMES; i++) {
                //有发包时间和收包时间，才计算收发时间差
                if (mSentDates[i] != null && mReceiveDates[i] != null) {
                    sum += mReceiveDates[i].getTime() - mSentDates[i].getTime();
                }
            }
            showLogMsg("丢包率为" + re + "% \n");
            //丢包率百分百时，不计算延时
            if (mReceiveTimes != 0) {
                avg = (double) sum / mReceiveTimes;
                avg /= 2;
                showLogMsg("平均延时" + avg + "ms\n");
            }
            close();
        }

        //  显示信息
        public void showLogMsg(String msg) {
            final SocketActivity activity = mActivityWeakReference.get();
            if (activity != null) {
                activity.onLogging(msg);
            }
        }
    }

}
